#!/usr/bin/env python3
"""
2FA安全检测工具 v3.0 - 用户友好版
Advanced Two-Factor Authentication Security Testing Tool

功能特点：
- 交互式用户界面，简单易用
- 智能目标检测，自动分析网站
- 一键安全测试，无需专业知识
- 详细报告生成，清晰易懂
- 中文界面支持，本土化体验

🔧 技术特性：
- 架构重构：argparse命令行参数、colorama输出、配置参数化
- CSRF处理：自动提取CSRF Token
- 精准计时：time.perf_counter()纳秒级精度
- TOTP支持：pyotp生成真实验证码
- 请求伪装：随机User-Agent和请求头管理
- 代码健壮性：类型提示、异常处理优化
- 代理支持：HTTP代理配合抓包调试
"""

import argparse
import random
import re
import string
import sys
import time
import logging
import os
from datetime import datetime
from datetime import datetime
from typing import Dict, List, Optional, Tuple, Union
from urllib.parse import urljoin, urlparse

import requests
import urllib3
from bs4 import BeautifulSoup
from colorama import Fore, Back, Style, init

# 初始化colorama
init(autoreset=True)

try:
    import pyotp
    TOTP_AVAILABLE = True
except ImportError:
    TOTP_AVAILABLE = False
    print(f"{Fore.YELLOW}警告: pyotp模块未安装，TOTP功能将不可用")

# 禁用SSL警告
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

class AdvancedTwoFactorAuthTester:
    """增强版2FA安全检测器"""
  
    def __init__(self, base_url: str, config: Optional[Dict] = None):
        """
        初始化2FA测试器
      
        Args:
            base_url: 目标网站基础URL
            config: 配置参数字典
        """
        self.base_url = base_url.rstrip('/')
        self.config = config or {}
        self.current_test_progress = 0
        self.total_tests = 7  # 总共有7个测试项目
        self.log_file = None
      
        # 默认配置
        self.default_config = {
            'timeout': 10,
            'max_retries': 3,
            'user_agents': [
                'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
                'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
                'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
                'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:121.0) Gecko/20100101 Firefox/121.0',
                'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:121.0) Gecko/20100101 Firefox/121.0'
            ],
            'proxy': None,
            'verify_ssl': False,
            'csrf_token_name': 'csrf_token',
            'max_timing_attempts': 5,
            'enable_logging': True,
            'log_level': 'INFO'
        }
      
        # 合并配置
        self.config = {**self.default_config, **self.config}
      
        # 设置日志
        self._setup_logging()
      
        # 初始化会话
        self.session = requests.Session()
        self.session.verify = self.config['verify_ssl']
      
        # 设置代理
        if self.config.get('proxy'):
            self.session.proxies = {
                'http': self.config['proxy'],
                'https': self.config['proxy']
            }
      
        # 设置重试
        adapter = requests.adapters.HTTPAdapter(
            max_retries=self.config['max_retries']
        )
        self.session.mount('http://', adapter)
        self.session.mount('https://', adapter)
      
        # 存储结果
        self.results = {
            'vulnerabilities': [],
            'recommendations': [],
            'detailed_analysis': {},
            'csrf_tokens': {},
            'timing_data': [],
            'test_start_time': None,
            'test_end_time': None
        }
      
        print(f"{Fore.CYAN}[*] 2FA安全检测器初始化完成")
        print(f"{Fore.CYAN}[*] 目标: {self.base_url}")
        print(f"{Fore.CYAN}[*] 代理: {self.config.get('proxy', '无')}")
        print(f"{Fore.CYAN}[*] SSL验证: {'开启' if self.config['verify_ssl'] else '关闭'}")
      
        # 术语解释
        self._print_terminology_explanation()
  
    def _setup_logging(self):
        """设置日志记录"""
        if self.config.get('enable_logging', True):
            # 创建logs目录
            log_dir = os.path.join(os.getcwd(), 'logs')
            if not os.path.exists(log_dir):
                os.makedirs(log_dir)
          
            # 生成日志文件名
            timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
            self.log_file = os.path.join(log_dir, f'2fa_test_{timestamp}.log')
          
            # 配置日志
            log_level = getattr(logging, self.config.get('log_level', 'INFO').upper())
            logging.basicConfig(
                level=log_level,
                format='%(asctime)s - %(levelname)s - %(message)s',
                handlers=[
                    logging.FileHandler(self.log_file, encoding='utf-8'),
                    logging.StreamHandler(sys.stdout)
                ]
            )
          
            self.logger = logging.getLogger(__name__)
            print(f"{Fore.GREEN}[+] 日志记录已启用，日志文件: {self.log_file}")
        else:
            # 如果禁用日志，仍然创建一个基本的logger用于控制台输出
            self.logger = logging.getLogger(__name__)
            self.logger.setLevel(logging.INFO)
            console_handler = logging.StreamHandler(sys.stdout)
            console_handler.setFormatter(logging.Formatter('%(asctime)s - %(levelname)s - %(message)s'))
            self.logger.addHandler(console_handler)
  
    def _print_terminology_explanation(self):
        """打印术语解释"""
        print(f"\n{Fore.CYAN}[*] 安全术语解释:")
        print(f"{Fore.WHITE}  - TOTP: 基于时间的一次性密码算法，每30秒生成新的验证码")
        print(f"{Fore.WHITE}  - CSRF: 跨站请求伪造攻击，通过伪造用户请求执行恶意操作")
        print(f"{Fore.WHITE}  - 时序攻击: 通过分析响应时间差异来破解系统的攻击方式")
        print(f"{Fore.WHITE}  - 暴力破解: 通过尝试大量可能的验证码来破解系统")
        print(f"{Fore.WHITE}  - 验证码重用: 同一个验证码可以被多次使用的安全漏洞")
        print()
  
    def _log_and_print(self, message: str, level: str = "INFO", color: str = Fore.WHITE):
        """同时记录日志和打印输出"""
        print(f"{color}{message}")
        if hasattr(self, 'logger'):
            log_method = getattr(self.logger, level.lower(), self.logger.info)
            log_method(message)
  
    def _update_progress(self, test_name: str, progress: int):
        """更新测试进度"""
        self.current_test_progress = progress
        percentage = (progress / self.total_tests) * 100
        progress_bar = f"{'█' * int(percentage / 10)}{'░' * (10 - int(percentage / 10))}"
        print(f"\n{Fore.CYAN}[{progress_bar}] {percentage:.1f}% - {test_name}")
        self._log_and_print(f"测试进度: {progress}/{self.total_tests} - {test_name}", "INFO", Fore.CYAN)
  
    def _get_random_headers(self) -> Dict[str, str]:
        """获取随机请求头"""
        user_agent = random.choice(self.config['user_agents'])
      
        headers = {
            'User-Agent': user_agent,
            'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
            'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
            'Accept-Encoding': 'gzip, deflate, br',
            'Connection': 'keep-alive',
            'Upgrade-Insecure-Requests': '1',
            'Sec-Fetch-Dest': 'document',
            'Sec-Fetch-Mode': 'navigate',
            'Sec-Fetch-Site': 'none',
            'Cache-Control': 'max-age=0'
        }
      
        return headers
  
    def _get_csrf_token(self, url: str) -> Optional[str]:
        """
        自动提取CSRF Token
      
        Args:
            url: 目标URL
          
        Returns:
            CSRF Token或None
        """
        try:
            headers = self._get_random_headers()
            response = self.session.get(url, headers=headers, timeout=self.config['timeout'])
            soup = BeautifulSoup(response.text, 'html.parser')
          
            # 常见的CSRF token字段名
            csrf_names = [
                'csrf_token', 'csrf_token', '_token', 'authenticity_token',
                'csrf', 'token', '_csrf', 'csrfmiddlewaretoken'
            ]
          
            # 查找input字段
            for name in csrf_names:
                csrf_input = soup.find('input', {'name': name})
                if csrf_input and csrf_input.get('value'):
                    token = csrf_input['value']
                    self.results['csrf_tokens'][url] = token
                    print(f"{Fore.GREEN}[+] 成功提取CSRF Token: {name}")
                    return token
          
            # 查找meta标签
            csrf_meta = soup.find('meta', {'name': 'csrf-token'})
            if csrf_meta and csrf_meta.get('content'):
                token = csrf_meta['content']
                self.results['csrf_tokens'][url] = token
                print(f"{Fore.GREEN}[+] 成功提取CSRF Token (meta): {token[:20]}...")
                return token
          
            print(f"{Fore.YELLOW}[-] 未找到CSRF Token")
            return None
          
        except Exception as e:
            print(f"{Fore.RED}[!] 提取CSRF Token失败: {str(e)}")
            return None
  
    def _generate_totp_code(self, secret: str) -> Optional[str]:
        """
        生成TOTP验证码
      
        Args:
            secret: TOTP密钥
          
        Returns:
            TOTP验证码或None
        """
        if not TOTP_AVAILABLE:
            print(f"{Fore.YELLOW}[!] pyotp未安装，无法生成TOTP验证码")
            return None
      
        try:
            totp = pyotp.TOTP(secret)
            code = totp.now()
            print(f"{Fore.GREEN}[+] 生成TOTP验证码: {code}")
            return code
        except Exception as e:
            print(f"{Fore.RED}[!] TOTP生成失败: {str(e)}")
            return None
  
    def _analyze_response(self, response: requests.Response, test_name: str) -> Dict:
        """
        分析HTTP响应
      
        Args:
            response: HTTP响应对象
            test_name: 测试名称
          
        Returns:
            分析结果字典
        """
        analysis = {
            'status_code': response.status_code,
            'content_length': len(response.content),
            'response_time': 0,  # 将在调用处计算
            'headers': dict(response.headers),
            'cookies': dict(response.cookies),
            'redirects': len(response.history),
            'vulnerabilities': []
        }
      
        # 检查常见漏洞模式
        if response.status_code == 200:
            # 检查是否包含敏感信息
            sensitive_patterns = [
                r'token["\']?\s*[:=]\s*["\']?([a-zA-Z0-9_-]{20,})',
                r'secret["\']?\s*[:=]\s*["\']?([a-zA-Z0-9_-]{16,})',
                r'password["\']?\s*[:=]\s*["\']?([^"\']+)',
                r'error["\']?\s*[:=]\s*["\']?([^"\']+)'
            ]
          
            for pattern in sensitive_patterns:
                matches = re.findall(pattern, response.text, re.IGNORECASE)
                if matches:
                    analysis['vulnerabilities'].append(f"可能的敏感信息泄露: {matches[0][:50]}...")
      
        return analysis
  
    def _generate_random_code(self, length: int = 6) -> str:
        """生成随机验证码"""
        return ''.join(random.choices(string.digits, k=length))
  
    def check_2fa_bypass_methods(self, login_url: str, valid_credentials: Optional[Tuple] = None) -> List[str]:
        """
        检测2FA绕过方法 - 增强版
      
        Args:
            login_url: 登录页面URL
            valid_credentials: 有效凭据元组 (username, password)
          
        Returns:
            漏洞列表
        """
        print(f"\n{Fore.CYAN}[*] 检测2FA绕过方法...")
        print(f"{Fore.WHITE}  说明: 测试是否存在空验证码、固定验证码等绕过方式")
        print(f"{Fore.WHITE}  风险: 攻击者可能绕过2FA验证直接登录系统")
        vulnerabilities = []
      
        try:
            # 获取CSRF Token
            csrf_token = self._get_csrf_token(login_url)
          
            # 获取登录页面
            headers = self._get_random_headers()
            response = self.session.get(login_url, headers=headers, timeout=self.config['timeout'])
            soup = BeautifulSoup(response.text, 'html.parser')
          
            # 1. 测试空验证码绕过
            print(f"{Fore.YELLOW}[*] 测试空验证码绕过...")
            login_data = self._prepare_login_data(soup, valid_credentials, csrf_token, '')
          
            start_time = time.perf_counter()
            response = self.session.post(login_url, data=login_data, headers=headers, timeout=self.config['timeout'])
            response_time = time.perf_counter() - start_time
          
            if self._is_successful_login(response):
                vulnerabilities.append(f"空验证码绕过成功 (响应时间: {response_time:.3f}s)")
                print(f"{Fore.RED}[!] 发现漏洞: 空验证码绕过")
          
            # 2. 测试固定验证码绕过
            print(f"{Fore.YELLOW}[*] 测试固定验证码绕过...")
            common_codes = ['000000', '111111', '123456', '999999', '0000', '1234']
          
            for code in common_codes:
                login_data = self._prepare_login_data(soup, valid_credentials, csrf_token, code)
              
                start_time = time.perf_counter()
                response = self.session.post(login_url, data=login_data, headers=headers, timeout=self.config['timeout'])
                response_time = time.perf_counter() - start_time
              
                if self._is_successful_login(response):
                    vulnerabilities.append(f"固定验证码绕过成功: {code} (响应时间: {response_time:.3f}s)")
                    print(f"{Fore.RED}[!] 发现漏洞: 固定验证码 {code} 绕过")
                    break
          
            # 3. 测试步骤缺失绕过
            print(f"{Fore.YELLOW}[*] 测试步骤缺失绕过...")
            # 尝试直接访问受保护页面
            protected_urls = ['/dashboard', '/admin', '/user/profile', '/home', '/account']
          
            for protected_url in protected_urls:
                full_url = urljoin(self.base_url, protected_url)
                try:
                    response = self.session.get(full_url, headers=headers, timeout=self.config['timeout'])
                    if response.status_code == 200 and 'login' not in response.url.lower():
                        vulnerabilities.append(f"步骤缺失绕过: 可直接访问 {protected_url}")
                        print(f"{Fore.RED}[!] 发现漏洞: 步骤缺失绕过 - {protected_url}")
                        break
                except:
                    continue
          
            # 4. 测试验证码参数名绕过
            print(f"{Fore.YELLOW}[*] 测试验证码参数名绕过...")
            alternative_names = ['otp', 'token', 'auth_code', 'verification_code', 'mfa_code']
          
            for alt_name in alternative_names:
                login_data_alt = login_data.copy()
                if 'code' in login_data_alt:
                    login_data_alt[alt_name] = login_data_alt.pop('code')
                else:
                    login_data_alt[alt_name] = '123456'
              
                start_time = time.perf_counter()
                response = self.session.post(login_url, data=login_data_alt, headers=headers, timeout=self.config['timeout'])
                response_time = time.perf_counter() - start_time
              
                if self._is_successful_login(response):
                    vulnerabilities.append(f"参数名绕过: 使用 {alt_name} 代替 code (响应时间: {response_time:.3f}s)")
                    print(f"{Fore.RED}[!] 发现漏洞: 参数名绕过 - {alt_name}")
                    break
          
            print(f"{Fore.GREEN}[+] 2FA绕过检测完成")
          
        except Exception as e:
            print(f"{Fore.RED}[!] 2FA绕过检测失败: {str(e)}")
      
        return vulnerabilities
  
    def _prepare_login_data(self, soup: BeautifulSoup, valid_credentials: Optional[Tuple], 
                           csrf_token: Optional[str], code: str) -> Dict[str, str]:
        """
        准备登录数据
      
        Args:
            soup: BeautifulSoup对象
            valid_credentials: 有效凭据
            csrf_token: CSRF Token
            code: 验证码
          
        Returns:
            登录数据字典
        """
        login_data = {}
      
        # 添加CSRF Token
        if csrf_token:
            login_data[self.config['csrf_token_name']] = csrf_token
      
        # 添加凭据
        if valid_credentials:
            username, password = valid_credentials
            # 查找表单字段名
            username_field = soup.find('input', {'type': 'text'}) or soup.find('input', {'name': re.compile('user|email|login', re.I)})
            password_field = soup.find('input', {'type': 'password'})
          
            if username_field and username_field.get('name'):
                login_data[username_field['name']] = username
            else:
                login_data['username'] = username
          
            if password_field and password_field.get('name'):
                login_data[password_field['name']] = password
            else:
                login_data['password'] = password
      
        # 添加验证码
        code_field = soup.find('input', {'type': 'text', 'name': re.compile('code|otp|token', re.I)})
        if code_field and code_field.get('name'):
            login_data[code_field['name']] = code
        else:
            login_data['code'] = code
      
        return login_data
  
    def _is_successful_login(self, response: requests.Response) -> bool:
        """
        判断是否为成功登录
      
        Args:
            response: HTTP响应
          
        Returns:
            是否成功登录
        """
        # 多种判断逻辑，不仅仅依赖状态码
        if response.status_code == 200:
            # 检查是否重定向到不同URL
            if response.url != response.request.url:
                return True
          
            # 检查响应内容
            content = response.text.lower()
            success_indicators = ['dashboard', 'welcome', 'profile', 'logout', 'success']
            failure_indicators = ['error', 'invalid', 'failed', 'incorrect', 'wrong']
          
            success_count = sum(1 for indicator in success_indicators if indicator in content)
            failure_count = sum(1 for indicator in failure_indicators if indicator in content)
          
            return success_count > failure_count
      
        return False
  
    def check_2fa_brute_force_protection(self, login_url: str, valid_credentials: Optional[Tuple] = None) -> List[str]:
        """
        检测2FA暴力破解保护 - 增强版
      
        Args:
            login_url: 登录页面URL
            valid_credentials: 有效凭据
          
        Returns:
            漏洞列表
        """
        print(f"\n{Fore.CYAN}[*] 检测2FA暴力破解保护...")
        print(f"{Fore.WHITE}  说明: 测试系统是否限制验证码错误尝试次数")
        print(f"{Fore.WHITE}  风险: 攻击者可能通过不断尝试破解验证码")
        vulnerabilities = []
      
        try:
            csrf_token = self._get_csrf_token(login_url)
            headers = self._get_random_headers()
            response = self.session.get(login_url, headers=headers, timeout=self.config['timeout'])
            soup = BeautifulSoup(response.text, 'html.parser')
          
            # 测试多次错误尝试
            print(f"{Fore.YELLOW}[*] 测试暴力破解保护...")
            error_responses = []
          
            for i in range(10):
                random_code = self._generate_random_code()
                login_data = self._prepare_login_data(soup, valid_credentials, csrf_token, random_code)
              
                start_time = time.perf_counter()
                response = self.session.post(login_url, data=login_data, headers=headers, timeout=self.config['timeout'])
                response_time = time.perf_counter() - start_time
              
                error_responses.append({
                    'attempt': i + 1,
                    'code': random_code,
                    'status_code': response.status_code,
                    'response_time': response_time,
                    'content_length': len(response.content),
                    'url': response.url
                })
              
                # 检查是否被锁定
                if 'locked' in response.text.lower() or 'blocked' in response.text.lower():
                    print(f"{Fore.GREEN}[+] 检测到账户锁定机制")
                    break
              
                time.sleep(0.5)  # 避免过快请求
          
            # 分析响应模式
            if len(error_responses) >= 5:
                # 检查响应时间模式
                response_times = [resp['response_time'] for resp in error_responses]
                avg_time = sum(response_times) / len(response_times)
                time_variance = sum((t - avg_time) ** 2 for t in response_times) / len(response_times)
              
                # 检查内容长度模式
                content_lengths = [resp['content_length'] for resp in error_responses]
                unique_lengths = len(set(content_lengths))
              
                if time_variance < 0.001 and unique_lengths == 1:
                    vulnerabilities.append("可能的暴力破解保护不足: 响应模式过于一致")
                    print(f"{Fore.RED}[!] 发现漏洞: 暴力破解保护不足")
              
                # 检查是否允许过多尝试
                if len(error_responses) >= 10:
                    vulnerabilities.append("暴力破解保护不足: 允许多次错误尝试")
                    print(f"{Fore.RED}[!] 发现漏洞: 允许多次错误尝试")
          
            print(f"{Fore.GREEN}[+] 暴力破解保护检测完成")
          
        except Exception as e:
            print(f"{Fore.RED}[!] 暴力破解保护检测失败: {str(e)}")
      
        return vulnerabilities
  
    def check_2fa_timing_attacks(self, login_url: str, valid_credentials: Optional[Tuple] = None) -> List[str]:
        """
        检测2FA时序攻击 - 增强版
      
        Args:
            login_url: 登录页面URL
            valid_credentials: 有效凭据
          
        Returns:
            漏洞列表
        """
        print(f"\n{Fore.CYAN}[*] 检测2FA时序攻击...")
        print(f"{Fore.WHITE}  说明: 测试系统对正确和错误验证码的响应时间差异")
        print(f"{Fore.WHITE}  风险: 攻击者可能通过响应时间判断验证码是否正确")
        vulnerabilities = []
      
        try:
            csrf_token = self._get_csrf_token(login_url)
            headers = self._get_random_headers()
            response = self.session.get(login_url, headers=headers, timeout=self.config['timeout'])
            soup = BeautifulSoup(response.text, 'html.parser')
          
            # 测试有效和无效验证码的响应时间差异
            print(f"{Fore.YELLOW}[*] 测试时序攻击...")
          
            # 生成测试验证码
            valid_code = "123456"  # 假设的有效验证码
            invalid_codes = [self._generate_random_code() for _ in range(self.config['max_timing_attempts'])]
          
            timing_results = {'valid': [], 'invalid': []}
          
            # 测试有效验证码（如果知道的话）
            if valid_credentials and TOTP_AVAILABLE:
                # 这里可以添加真实的TOTP验证码测试
                pass
          
            # 测试无效验证码
            for invalid_code in invalid_codes:
                login_data = self._prepare_login_data(soup, valid_credentials, csrf_token, invalid_code)
              
                start_time = time.perf_counter()
                response = self.session.post(login_url, data=login_data, headers=headers, timeout=self.config['timeout'])
                response_time = time.perf_counter() - start_time
              
                timing_results['invalid'].append(response_time)
              
                time.sleep(0.1)  # 短暂延迟
          
            # 分析时序差异
            if len(timing_results['invalid']) >= 3:
                invalid_times = timing_results['invalid']
                avg_invalid = sum(invalid_times) / len(invalid_times)
                time_variance = sum((t - avg_invalid) ** 2 for t in invalid_times) / len(invalid_times)
              
                # 如果方差很小，可能存在时序攻击漏洞
                if time_variance < 0.0001:
                    vulnerabilities.append(f"可能的时序攻击漏洞: 响应时间过于一致 (方差: {time_variance:.6f})")
                    print(f"{Fore.RED}[!] 发现漏洞: 时序攻击漏洞")
          
            print(f"{Fore.GREEN}[+] 时序攻击检测完成")
          
        except Exception as e:
            print(f"{Fore.RED}[!] 时序攻击检测失败: {str(e)}")
      
        return vulnerabilities
  
    def check_2fa_code_reuse(self, login_url: str, valid_credentials: Optional[Tuple] = None) -> List[str]:
        """
        检测2FA验证码重用 - 增强版
      
        Args:
            login_url: 登录页面URL
            valid_credentials: 有效凭据
          
        Returns:
            漏洞列表
        """
        print(f"\n{Fore.CYAN}[*] 检测2FA验证码重用...")
        vulnerabilities = []
      
        try:
            csrf_token = self._get_csrf_token(login_url)
            headers = self._get_random_headers()
            response = self.session.get(login_url, headers=headers, timeout=self.config['timeout'])
            soup = BeautifulSoup(response.text, 'html.parser')
          
            # 使用相同的验证码多次尝试
            print(f"{Fore.YELLOW}[*] 测试验证码重用...")
            test_code = self._generate_random_code()
          
            reuse_results = []
            for i in range(3):
                login_data = self._prepare_login_data(soup, valid_credentials, csrf_token, test_code)
              
                start_time = time.perf_counter()
                response = self.session.post(login_url, data=login_data, headers=headers, timeout=self.config['timeout'])
                response_time = time.perf_counter() - start_time
              
                reuse_results.append({
                    'attempt': i + 1,
                    'status_code': response.status_code,
                    'response_time': response_time,
                    'content_length': len(response.content),
                    'success': self._is_successful_login(response)
                })
              
                time.sleep(0.5)
          
            # 分析重用结果
            if len(reuse_results) >= 2:
                # 检查是否有成功的情况
                successful_attempts = sum(1 for result in reuse_results if result['success'])
              
                if successful_attempts > 1:
                    vulnerabilities.append(f"验证码重用漏洞: 同一验证码成功使用 {successful_attempts} 次")
                    print(f"{Fore.RED}[!] 发现漏洞: 验证码重用")
              
                # 检查响应模式
                status_codes = [result['status_code'] for result in reuse_results]
                if len(set(status_codes)) == 1:
                    # 检查内容长度
                    content_lengths = [result['content_length'] for result in reuse_results]
                    if len(set(content_lengths)) == 1:
                        vulnerabilities.append("可能的验证码重用: 响应模式完全一致")
                        print(f"{Fore.YELLOW}[!] 可疑: 可能的验证码重用")
          
            print(f"{Fore.GREEN}[+] 验证码重用检测完成")
          
        except Exception as e:
            print(f"{Fore.RED}[!] 验证码重用检测失败: {str(e)}")
      
        return vulnerabilities
  
    def check_2fa_code_lifetime(self, login_url: str, valid_credentials: Optional[Tuple] = None) -> List[str]:
        """
        检测2FA验证码有效期 - 增强版
      
        Args:
            login_url: 登录页面URL
            valid_credentials: 有效凭据
          
        Returns:
            漏洞列表
        """
        print(f"\n{Fore.CYAN}[*] 检测2FA验证码有效期...")
        vulnerabilities = []
      
        try:
            # 这里可以添加更复杂的有效期测试
            # 由于需要实际的验证码，这里只做基本检测
            print(f"{Fore.YELLOW}[*] 测试验证码有效期...")
          
            # 检查页面是否有有效期提示
            headers = self._get_random_headers()
            response = self.session.get(login_url, headers=headers, timeout=self.config['timeout'])
          
            content = response.text.lower()
            lifetime_indicators = [
                'expire', 'valid', 'lifetime', 'duration',
                'timeout', '分钟', '小时', '秒'
            ]
          
            found_indicators = []
            for indicator in lifetime_indicators:
                if indicator in content:
                    found_indicators.append(indicator)
          
            if not found_indicators:
                vulnerabilities.append("未找到验证码有效期提示")
                print(f"{Fore.YELLOW}[!] 警告: 未找到有效期提示")
          
            print(f"{Fore.GREEN}[+] 验证码有效期检测完成")
          
        except Exception as e:
            print(f"{Fore.RED}[!] 验证码有效期检测失败: {str(e)}")
      
        return vulnerabilities
  
    def check_2fa_optional_enforcement(self, login_url: str, valid_credentials: Optional[Tuple] = None) -> List[str]:
        """
        检测2FA可选强制执行 - 增强版
      
        Args:
            login_url: 登录页面URL
            valid_credentials: 有效凭据
          
        Returns:
            漏洞列表
        """
        print(f"\n{Fore.CYAN}[*] 检测2FA可选强制执行...")
        vulnerabilities = []
      
        try:
            # 检查是否存在跳过2FA的选项
            headers = self._get_random_headers()
            response = self.session.get(login_url, headers=headers, timeout=self.config['timeout'])
            soup = BeautifulSoup(response.text, 'html.parser')
          
            # 查找跳过链接或按钮
            skip_links = soup.find_all('a', string=re.compile('跳过|skip|later|稍后', re.I))
            skip_buttons = soup.find_all('button', string=re.compile('跳过|skip|later|稍后', re.I))
          
            if skip_links or skip_buttons:
                vulnerabilities.append("发现跳过2FA的选项")
                print(f"{Fore.RED}[!] 发现漏洞: 存在跳过2FA选项")
          
            # 检查是否存在"稍后设置"选项
            later_options = soup.find_all(['a', 'button'], string=re.compile('later|稍后|以后', re.I))
            if later_options:
                vulnerabilities.append("发现延后设置2FA的选项")
                print(f"{Fore.YELLOW}[!] 警告: 存在延后设置选项")
          
            print(f"{Fore.GREEN}[+] 2FA强制执行检测完成")
          
        except Exception as e:
            print(f"{Fore.RED}[!] 2FA强制执行检测失败: {str(e)}")
      
        return vulnerabilities
  
    def check_2fa_implementation_gaps(self, login_url: str) -> List[str]:
        """
        检测2FA实现缺陷 - 增强版
      
        Args:
            login_url: 登录页面URL
          
        Returns:
            漏洞列表
        """
        print(f"\n{Fore.CYAN}[*] 检测2FA实现缺陷...")
        vulnerabilities = []
      
        try:
            headers = self._get_random_headers()
            response = self.session.get(login_url, headers=headers, timeout=self.config['timeout'])
            soup = BeautifulSoup(response.text, 'html.parser')
          
            # 1. 检查是否存在2FA相关隐藏字段
            hidden_inputs = soup.find_all('input', {'type': 'hidden'})
            for input_field in hidden_inputs:
                field_name = input_field.get('name', '').lower()
                if any(keyword in field_name for keyword in ['token', 'code', 'otp', '2fa']):
                    vulnerabilities.append(f"2FA相关隐藏字段暴露: {field_name}")
                    print(f"{Fore.YELLOW}[!] 警告: 隐藏字段暴露 - {field_name}")
          
            # 2. 检查JavaScript中是否包含2FA相关代码
            scripts = soup.find_all('script')
            for script in scripts:
                script_content = script.get_text()
                if any(keyword in script_content.lower() for keyword in ['otp', 'code', '2fa', 'token']):
                    vulnerabilities.append("2FA相关代码可能在前端暴露")
                    print(f"{Fore.YELLOW}[!] 警告: 前端代码暴露")
                    break
          
            # 3. 检查是否存在调试信息
            debug_patterns = [
                r'console\.log|debug|console\.error',
                r'token.*=.*["\']|code.*=.*["\']',
                r'secret.*=.*["\']|password.*=.*["\']'
            ]
          
            for pattern in debug_patterns:
                matches = re.findall(pattern, response.text, re.IGNORECASE)
                if matches:
                    vulnerabilities.append(f"发现可能的调试信息泄露: {matches[:3]}")
                    print(f"{Fore.RED}[!] 发现漏洞: 调试信息泄露")
                    break
          
            # 4. 检查是否使用HTTPS
            if not login_url.startswith('https://'):
                vulnerabilities.append("未使用HTTPS传输")
                print(f"{Fore.RED}[!] 发现漏洞: 未使用HTTPS")
          
            print(f"{Fore.GREEN}[+] 实现缺陷检测完成")
          
        except Exception as e:
            print(f"{Fore.RED}[!] 实现缺陷检测失败: {str(e)}")
      
        return vulnerabilities
  
    def run_comprehensive_2fa_test(self, login_url: str, valid_credentials: Optional[Tuple] = None, 
                                 totp_secret: Optional[str] = None) -> Dict:
        """
        运行全面的2FA安全测试 - 增强版
      
        Args:
            login_url: 登录页面URL
            valid_credentials: 有效凭据
            totp_secret: TOTP密钥
          
        Returns:
            测试结果字典
        """
        self.results['test_start_time'] = datetime.now()
      
        print(f"\n{Fore.CYAN}{'='*60}")
        print(f"{Fore.CYAN}[*] 开始全面2FA安全测试")
        print(f"{Fore.CYAN}[*] 目标: {self.base_url}")
        print(f"{Fore.CYAN}[*] 登录URL: {login_url}")
        print(f"{Fore.CYAN}{'='*60}")
      
        self._log_and_print(f"开始全面2FA安全测试，目标: {self.base_url}, 登录URL: {login_url}", "INFO", Fore.CYAN)
      
        # 获取基础页面信息
        self._get_base_page_info()
      
        # 如果提供了TOTP密钥，生成验证码
        if totp_secret and TOTP_AVAILABLE:
            print(f"{Fore.GREEN}[+] 使用TOTP密钥生成验证码")
            valid_code = self._generate_totp_code(totp_secret)
            self._log_and_print(f"使用TOTP密钥生成验证码: {valid_code}", "INFO", Fore.GREEN)
        else:
            valid_code = None
            self._log_and_print("未提供TOTP密钥，跳过TOTP验证码生成", "INFO", Fore.YELLOW)
      
        # 执行各项测试
        tests_results = {}
        test_names = {
            'bypass_methods': '2FA绕过方法检测',
            'brute_force': '暴力破解保护检测',
            'timing_attacks': '时序攻击检测',
            'code_reuse': '验证码重用检测',
            'code_lifetime': '验证码有效期检测',
            'optional_enforcement': '2FA强制执行检测',
            'implementation_gaps': '实现缺陷检测'
        }
      
        print(f"\n{Fore.YELLOW}[*] 执行各项安全测试...")
        self._log_and_print("开始执行各项安全测试", "INFO", Fore.YELLOW)
      
        # 定义测试函数映射
        test_functions = [
            ('bypass_methods', self.check_2fa_bypass_methods, '2FA绕过方法检测'),
            ('brute_force', self.check_2fa_brute_force_protection, '暴力破解保护检测'),
            ('timing_attacks', self.check_2fa_timing_attacks, '时序攻击检测'),
            ('code_reuse', self.check_2fa_code_reuse, '验证码重用检测'),
            ('code_lifetime', self.check_2fa_code_lifetime, '验证码有效期检测'),
            ('optional_enforcement', self.check_2fa_optional_enforcement, '2FA强制执行检测'),
            ('implementation_gaps', self.check_2fa_implementation_gaps, '实现缺陷检测')
        ]
      
        for i, (test_key, test_func, test_name) in enumerate(test_functions, 1):
            self._update_progress(test_name, i)
            self._log_and_print(f"开始执行: {test_name}", "INFO", Fore.CYAN)
          
            try:
                start_time = time.time()
                result = test_func(login_url, valid_credentials)
                end_time = time.time()
              
                tests_results[test_key] = result
                self._log_and_print(f"完成: {test_name}，发现 {len(result)} 个问题，耗时: {end_time - start_time:.2f}秒", 
                                  "INFO", Fore.GREEN if len(result) == 0 else Fore.RED)
              
            except Exception as e:
                self._log_and_print(f"测试 {test_name} 失败: {str(e)}", "ERROR", Fore.RED)
                tests_results[test_key] = []
      
        # 完成所有测试
        self._update_progress("所有测试完成", self.total_tests)
      
        # 合并所有漏洞
        all_vulnerabilities = []
        for test_name, results in tests_results.items():
            all_vulnerabilities.extend(results)
      
        self.results['vulnerabilities'] = all_vulnerabilities
        self.results['detailed_analysis'] = tests_results
        self.results['test_end_time'] = datetime.now()
      
        # 生成安全建议
        recommendations = self.generate_recommendations(all_vulnerabilities)
        self.results['recommendations'] = recommendations
      
        # 记录测试总结
        test_duration = self.results['test_end_time'] - self.results['test_start_time']
        self._log_and_print(f"测试完成总结: 发现 {len(all_vulnerabilities)} 个安全问题，耗时: {test_duration}", 
                          "INFO", Fore.CYAN)
      
        return self.results
  
    def _get_base_page_info(self):
        """获取基础页面信息"""
        try:
            headers = self._get_random_headers()
            response = self.session.get(self.base_url, headers=headers, timeout=self.config['timeout'])
            print(f"{Fore.GREEN}[+] 成功连接目标网站")
            print(f"{Fore.GREEN}[+] 服务器: {response.headers.get('Server', '未知')}")
            print(f"{Fore.GREEN}[+] 状态码: {response.status_code}")
        except Exception as e:
            print(f"{Fore.RED}[!] 连接目标网站失败: {str(e)}")
  
    def generate_recommendations(self, vulnerabilities: List[str]) -> List[str]:
        """
        生成安全建议 - 增强版
      
        Args:
            vulnerabilities: 漏洞列表
          
        Returns:
            建议列表
        """
        recommendations = []
      
        vuln_text = " ".join(vulnerabilities).lower()
      
        if any(keyword in vuln_text for keyword in ["绕过", "bypass"]):
            recommendations.append("1. 实施严格的2FA验证逻辑，不允许空值、默认值或固定值绕过")
      
        if any(keyword in vuln_text for keyword in ["暴力破解", "brute force"]):
            recommendations.append("2. 实施2FA验证码尝试次数限制和账户锁定机制")
      
        if any(keyword in vuln_text for keyword in ["会话", "session"]):
            recommendations.append("3. 加强2FA会话管理，确保验证后会话正确更新和安全传输")
      
        if any(keyword in vuln_text for keyword in ["暴露", "expose"]):
            recommendations.append("4. 避免在前端暴露2FA相关敏感信息和逻辑")
      
        if any(keyword in vuln_text for keyword in ["时序", "timing"]):
            recommendations.append("5. 实施恒定时间验证，防止时序攻击")
      
        if any(keyword in vuln_text for keyword in ["重用", "reuse"]):
            recommendations.append("6. 确保验证码一次性使用，防止重用攻击")
      
        if any(keyword in vuln_text for keyword in ["有效期", "lifetime"]):
            recommendations.append("7. 设置合理的验证码有效期，通常为30-60秒")
      
        if any(keyword in vuln_text for keyword in ["csrf", "token"]):
            recommendations.append("8. 正确实施CSRF保护机制")
      
        if any(keyword in vuln_text for keyword in ["https", "ssl"]):
            recommendations.append("9. 使用HTTPS加密传输所有敏感数据")
      
        if not recommendations:
            recommendations.append("✓ 未发现明显的2FA安全问题")
      
        return recommendations
  
    def print_detailed_report(self):
        """打印详细报告 - 增强版"""
        print(f"\n{Fore.CYAN}{'='*60}")
        print(f"{Fore.CYAN}2FA安全检测详细报告")
        print(f"{Fore.CYAN}{'='*60}")
        print(f"{Fore.WHITE}目标URL: {self.base_url}")
        print(f"{Fore.WHITE}检测时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
        print(f"{Fore.WHITE}工具版本: 2FA安全检测工具 v3.0 (优化版)")
      
        # 显示测试时间统计
        if self.results.get('test_start_time') and self.results.get('test_end_time'):
            test_duration = self.results['test_end_time'] - self.results['test_start_time']
            print(f"{Fore.WHITE}测试耗时: {test_duration}")
      
        # 显示日志文件信息
        if self.log_file:
            print(f"{Fore.WHITE}日志文件: {self.log_file}")
      
        print()
      
        vulnerabilities = self.results['vulnerabilities']
        recommendations = self.results['recommendations']
        detailed_analysis = self.results['detailed_analysis']
      
        # 按测试类型分类显示
        print(f"{Fore.YELLOW}详细测试结果:")
        print(f"{Fore.WHITE}-" * 40)
      
        for test_name, results in detailed_analysis.items():
            if results:
                test_title = test_name.replace('_', ' ').title()
                print(f"\n{Fore.CYAN}{test_title}:")
                for result in results:
                    print(f"{Fore.RED}  • {result}")
      
        print()
        print(f"{Fore.YELLOW}发现的安全问题:")
        print(f"{Fore.WHITE}-" * 40)
        if vulnerabilities:
            for i, vuln in enumerate(vulnerabilities, 1):
                print(f"{Fore.RED}{i}. {vuln}")
        else:
            print(f"{Fore.GREEN}✓ 未发现明显的2FA安全问题")
      
        print()
        print(f"{Fore.YELLOW}安全建议:")
        print(f"{Fore.WHITE}-" * 40)
        for rec in recommendations:
            if rec.startswith('✓'):
                print(f"{Fore.GREEN}• {rec}")
            else:
                print(f"{Fore.CYAN}• {rec}")
      
        print()
      
        # 风险等级评估
        print(f"{Fore.YELLOW}风险等级评估:")
        print(f"{Fore.WHITE}-" * 40)
        vuln_count = len(vulnerabilities)
        if vuln_count == 0:
            risk_level = f"{Fore.GREEN}低风险"
        elif vuln_count <= 3:
            risk_level = f"{Fore.YELLOW}中等风险"
        elif vuln_count <= 6:
            risk_level = f"{Fore.RED}高风险"
        else:
            risk_level = f"{Fore.RED}严重风险"
      
        print(f"{Fore.WHITE}当前风险等级: {risk_level}")
        print(f"{Fore.WHITE}发现漏洞数量: {vuln_count}")
      
        # 显示CSRF Token信息
        if self.results['csrf_tokens']:
            print()
            print(f"{Fore.YELLOW}CSRF Token信息:")
            print(f"{Fore.WHITE}-" * 40)
            for url, token in self.results['csrf_tokens'].items():
                print(f"{Fore.CYAN}  {url}: {token[:20]}...")
      
        print(f"{Fore.CYAN}{'='*60}")

def create_sample_config() -> Dict:
    """创建示例配置"""
    return {
        'timeout': 15,
        'max_retries': 5,
        'proxy': None,  # 'http://127.0.0.1:8080'
        'verify_ssl': False,
        'csrf_token_name': 'csrf_token',
        'max_timing_attempts': 10,
        'user_agents': [
            'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
            'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
            'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
        ]
    }

def interactive_setup():
    """交互式设置向导"""
    print(f"\n{Fore.CYAN}{'='*60}{Style.RESET_ALL}")
    print(f"{Fore.CYAN}[*] 欢迎使用2FA安全检测工具 - 用户友好版{Style.RESET_ALL}")
    print(f"{Fore.CYAN}{'='*60}{Style.RESET_ALL}")
  
    print(f"\n{Fore.YELLOW}📋 本工具将帮助您检测网站的双因素认证安全性{Style.RESET_ALL}")
    print(f"{Fore.GREEN}[*] 提示：请确保您有权限测试目标网站{Style.RESET_ALL}")
  
    # 获取目标信息
    print(f"\n{Fore.CYAN}🌐 第一步：设置目标网站{Style.RESET_ALL}")
    target = input(f"{Fore.WHITE}请输入目标网站URL (例如: https://example.com): {Style.RESET_ALL}").strip()
    if not target:
        print(f"{Fore.RED}[!] 目标URL不能为空{Style.RESET_ALL}")
        return None
  
    # 自动检测登录页面
    login_path = input(f"{Fore.WHITE}请输入登录页面路径 (默认: /login，直接回车使用默认): {Style.RESET_ALL}").strip()
    if not login_path:
        login_path = "/login"
  
    print(f"\n{Fore.CYAN}👤 第二步：设置登录凭据{Style.RESET_ALL}")
    username = input(f"{Fore.WHITE}请输入测试用户名: {Style.RESET_ALL}").strip()
    if not username:
        print(f"{Fore.RED}[!] 用户名不能为空{Style.RESET_ALL}")
        return None
  
    password = input(f"{Fore.WHITE}请输入测试密码: {Style.RESET_ALL}").strip()
    if not password:
        print(f"{Fore.RED}[!] 密码不能为空{Style.RESET_ALL}")
        return None
  
    print(f"\n{Fore.CYAN}[*] 第三步：设置2FA信息（可选）{Style.RESET_ALL}")
    has_totp = input(f"{Fore.WHITE}目标网站是否使用TOTP 2FA? (y/N): {Style.RESET_ALL}").strip().lower()
    totp_secret = None
    if has_totp == 'y':
        totp_secret = input(f"{Fore.WHITE}请输入TOTP密钥 (可选，留空将生成随机密钥): {Style.RESET_ALL}").strip()
        if not totp_secret:
            totp_secret = None
            print(f"{Fore.YELLOW}ℹ️ 将使用随机TOTP密钥进行测试{Style.RESET_ALL}")
  
    print(f"\n{Fore.CYAN}⚙️ 第四步：高级设置（可选）{Style.RESET_ALL}")
    use_proxy = input(f"{Fore.WHITE}是否使用HTTP代理? (y/N): {Style.RESET_ALL}").strip().lower()
    proxy = None
    if use_proxy == 'y':
        proxy = input(f"{Fore.WHITE}请输入代理地址 (例如: http://127.0.0.1:8080): {Style.RESET_ALL}").strip()
  
    # 确认设置
    print(f"\n{Fore.CYAN}📋 配置确认{Style.RESET_ALL}")
    print(f"{Fore.WHITE}目标网站: {target}{Style.RESET_ALL}")
    print(f"{Fore.WHITE}登录路径: {login_path}{Style.RESET_ALL}")
    print(f"{Fore.WHITE}测试用户: {username}{Style.RESET_ALL}")
    print(f"{Fore.WHITE}TOTP支持: {'是' if totp_secret else '否'}{Style.RESET_ALL}")
    print(f"{Fore.WHITE}代理设置: {proxy if proxy else '无'}{Style.RESET_ALL}")
  
    confirm = input(f"\n{Fore.YELLOW}是否确认以上设置并开始测试? (Y/n): {Style.RESET_ALL}").strip().lower()
    if confirm == 'n':
        print(f"{Fore.YELLOW}[*] 已取消，请重新运行程序{Style.RESET_ALL}")
        return None
  
    return {
        'target': target,
        'login_path': login_path,
        'username': username,
        'password': password,
        'totp_secret': totp_secret,
        'proxy': proxy,
        'timeout': 30,
        'max_retries': 3
    }

def print_usage_guide():
    """打印使用指南"""
    print(f"\n{Fore.CYAN}{'='*60}{Style.RESET_ALL}")
    print(f"{Fore.CYAN}📖 使用指南{Style.RESET_ALL}")
    print(f"{Fore.CYAN}{'='*60}{Style.RESET_ALL}")
  
    print(f"\n{Fore.GREEN}[*] 快速开始：{Style.RESET_ALL}")
    print(f"  1. 直接运行程序，按提示输入目标信息")
    print(f"  2. 程序会自动引导您完成测试配置")
    print(f"  3. 测试完成后会生成详细的安全报告")
  
    print(f"\n{Fore.YELLOW}⚡ 高级用户：{Style.RESET_ALL}")
    print(f"  使用命令行参数进行自动化测试：")
    print(f"  python 2fa_optimized.py --target https://example.com --username admin --password admin123")
  
    print(f"\n{Fore.BLUE}📋 参数说明：{Style.RESET_ALL}")
    print(f"  --target, -t     : 目标网站URL (必需)")
    print(f"  --login-path, -l : 登录页面路径 (默认: /login)")
    print(f"  --username, -u   : 测试用户名 (必需)")
    print(f"  --password, -p   : 测试密码 (必需)")
    print(f"  --totp-secret, -s: TOTP密钥 (可选)")
    print(f"  --proxy, -x      : HTTP代理地址 (可选)")
    print(f"  --timeout        : 请求超时时间 (默认: 30秒)")
    print(f"  --max-retries, -r: 最大重试次数 (默认: 3)")
    print(f"  --config, -c     : 配置文件路径 (JSON格式)")
  
    print(f"\n{Fore.MAGENTA}[*] 安全提醒：{Style.RESET_ALL}")
    print(f"  - 请确保您有权限测试目标网站")
    print(f"  - 建议在测试环境中使用本工具")
    print(f"  - 遵守相关法律法规和道德准则")

def main():
    """主函数 - 用户友好版"""
  
    # 检查是否有命令行参数
    if len(sys.argv) > 1:
        # 使用命令行模式
        parser = argparse.ArgumentParser(
            description='2FA安全检测工具 v3.0 - 用户友好版',
            formatter_class=argparse.RawDescriptionHelpFormatter,
            epilog="""
使用示例:
  python 2fa_optimized.py --target https://example.com --username admin --password admin123
  python 2fa_optimized.py --target https://example.com --username admin --password admin123 --totp-secret JBSWY3DPEHPK3PXP
  python 2fa_optimized.py --target https://example.com --username admin --password admin123 --proxy http://127.0.0.1:8080

交互式模式:
  python 2fa_optimized.py
        """
        )
      
        # 添加参数
        parser.add_argument("--target", "-t",
                           help="目标URL (例如: https://example.com)")
        parser.add_argument("--login-path", "-l", default="/login",
                           help="登录页面路径 (默认: /login)")
        parser.add_argument("--username", "-u",
                           help="用户名")
        parser.add_argument("--password", "-p",
                           help="密码")
        parser.add_argument("--totp-secret", "-s",
                           help="TOTP密钥 (可选)")
        parser.add_argument("--proxy", "-x",
                           help="HTTP代理地址 (例如: http://127.0.0.1:8080)")
        parser.add_argument("--timeout", default=30, type=int,
                           help="请求超时时间 (默认: 30秒)")
        parser.add_argument("--max-retries", "-r", default=3, type=int,
                           help="最大重试次数 (默认: 3)")
        parser.add_argument("--config", "-c",
                           help="配置文件路径 (JSON格式)")
      
        args = parser.parse_args()
      
        # 验证必需参数
        if not args.target or not args.username or not args.password:
            print(f"{Fore.RED}[!] 错误：目标URL、用户名和密码是必需参数{Style.RESET_ALL}")
            print_usage_guide()
            return 1
      
        config = {
            'target': args.target,
            'login_path': args.login_path,
            'username': args.username,
            'password': args.password,
            'totp_secret': args.totp_secret,
            'proxy': args.proxy,
            'timeout': args.timeout,
            'max_retries': args.max_retries
        }
    else:
        # 使用交互式模式
        config = interactive_setup()
        if not config:
            print(f"\n{Fore.YELLOW}[*] 感谢使用，再见！{Style.RESET_ALL}")
            return 0
  
    # 创建测试器实例
    tester_config = {
        'login_path': config['login_path'],
        'username': config['username'],
        'password': config['password'],
        'totp_secret': config.get('totp_secret'),
        'proxy': config.get('proxy'),
        'timeout': config.get('timeout', 30),
        'max_retries': config.get('max_retries', 3)
    }
  
    tester = AdvancedTwoFactorAuthTester(
        base_url=config['target'],
        config=tester_config
    )
  
    # 执行测试
    print(f"\n{Fore.CYAN}{'='*60}{Style.RESET_ALL}")
    print(f"{Fore.CYAN}[*] 开始2FA安全检测...{Style.RESET_ALL}")
    print(f"{Fore.CYAN}{'='*60}{Style.RESET_ALL}")
    print(f"{Fore.YELLOW}[*] 目标: {config['target']}{Style.RESET_ALL}")
    print(f"{Fore.YELLOW}[*] 用户: {config['username']}{Style.RESET_ALL}")
    print(f"{Fore.YELLOW}[*] TOTP: {'启用' if config.get('totp_secret') else '未启用'}{Style.RESET_ALL}")
  
    try:
        login_url = f"{config['target']}{config['login_path']}"
        credentials = (config['username'], config['password'])
        totp_secret = config.get('totp_secret')
      
        result = tester.run_comprehensive_2fa_test(
            login_url=login_url,
            valid_credentials=credentials,
            totp_secret=totp_secret
        )
      
        # 显示结果
        print(f"\n{Fore.GREEN}[+] 测试完成！{Style.RESET_ALL}")
        print(f"\n{Fore.CYAN}{'='*60}{Style.RESET_ALL}")
        print(f"{Fore.CYAN}📊 安全检测报告{Style.RESET_ALL}")
        print(f"{Fore.CYAN}{'='*60}{Style.RESET_ALL}")
      
        # 基本信息
        print(f"\n{Fore.YELLOW}🔍 基本信息:{Style.RESET_ALL}")
        print(f"  🌐 目标网站: {config['target']}")
        print(f"  👤 测试用户: {config['username']}")
        print(f"  ⏱️  响应时间: {result.get('response_time', 0):.4f}秒")
        print(f"  📡 状态码: {result.get('status_code', 'N/A')}")
      
        # 安全检测结果
        vulnerabilities = result.get('vulnerabilities', [])
        if vulnerabilities:
            print(f"\n{Fore.RED}🚨 发现的安全问题 ({len(vulnerabilities)}个):{Style.RESET_ALL}")
            for i, vuln in enumerate(vulnerabilities, 1):
                print(f"  {i}. {vuln}")
        else:
            print(f"\n{Fore.GREEN}[+] 未发现明显的安全问题{Style.RESET_ALL}")
      
        # CSRF检测
        csrf_token = result.get('csrf_token')
        if csrf_token:
            print(f"\n{Fore.GREEN}[+] CSRF保护: 检测到CSRF Token{Style.RESET_ALL}")
        else:
            print(f"\n{Fore.YELLOW}[-] CSRF保护: 未检测到CSRF Token{Style.RESET_ALL}")
      
        # TOTP检测
        if config.get('totp_secret'):
            print(f"\n{Fore.GREEN}[+] TOTP验证: 已配置并测试{Style.RESET_ALL}")
      
        # 安全建议
        print(f"\n{Fore.CYAN}[*] 安全建议:{Style.RESET_ALL}")
        if vulnerabilities:
            print(f"  [!] 建议立即修复发现的安全问题")
        else:
            print(f"  [+] 当前配置看起来比较安全")
      
        print(f"  📋 通用建议:")
        print(f"     - 确保2FA验证在所有登录场景下都启用")
        print(f"     - 实施账户锁定机制防止暴力破解")
        print(f"     - 使用安全的TOTP密钥存储方案")
        print(f"     - 定期更新和轮换2FA密钥")
        print(f"     - 监控异常登录行为")
      
        # 详细报告
        print(f"\n{Fore.CYAN}{'='*60}{Style.RESET_ALL}")
        print(f"{Fore.CYAN}📋 详细报告已生成，请查看完整分析结果{Style.RESET_ALL}")
        if tester.log_file:
            print(f"{Fore.CYAN}📝 测试日志已保存至: {tester.log_file}{Style.RESET_ALL}")
        print(f"{Fore.CYAN}{'='*60}{Style.RESET_ALL}")
      
        # 显示详细报告
        tester.print_detailed_report()
      
        # 生成报告文件
        try:
            report_file = generate_report_file(result, config, tester.log_file)
            print(f"\n{Fore.GREEN}[+] 完整报告已保存至: {report_file}{Style.RESET_ALL}")
        except Exception as e:
            print(f"\n{Fore.YELLOW}⚠️  报告文件生成失败: {str(e)}{Style.RESET_ALL}")
            import traceback
            traceback.print_exc()
      
    except KeyboardInterrupt:
        print(f"\n{Fore.YELLOW}⚠️  用户中断测试{Style.RESET_ALL}")
        return 1
    except Exception as e:
        print(f"\n{Fore.RED}[!] 测试失败: {str(e)}{Style.RESET_ALL}")
        print(f"{Fore.YELLOW}[*] 建议检查:{Style.RESET_ALL}")
        print(f"  - 目标网站是否可访问")
        print(f"  - 登录凭据是否正确")
        print(f"  - 网络连接是否正常")
        print(f"  - 是否有防火墙阻止访问")
        return 1
  
    print(f"\n{Fore.GREEN}[*] 感谢使用2FA安全检测工具！{Style.RESET_ALL}")
    print(f"{Fore.CYAN}[*] 再见！{Style.RESET_ALL}")
    return 0

def generate_report_file(result: Dict, config: Dict, log_file: Optional[str] = None) -> str:
    """生成详细的报告文件"""
    # 创建reports目录
    report_dir = os.path.join(os.getcwd(), 'reports')
    if not os.path.exists(report_dir):
        os.makedirs(report_dir)
  
    # 生成报告文件名
    timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
    report_file = os.path.join(report_dir, f'2fa_security_report_{timestamp}.txt')
  
    try:
        with open(report_file, 'w', encoding='utf-8') as f:
            f.write("=" * 80 + "\n")
            f.write("2FA安全检测报告\n")
            f.write(f"生成时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")
            f.write("=" * 80 + "\n\n")
          
            # 测试配置信息
            f.write("测试配置:\n")
            f.write(f"目标网站: {config.get('target', '未知')}\n")
            f.write(f"登录路径: {config.get('login_path', '/login')}\n")
            f.write(f"测试用户: {config.get('username', '未知')}\n")
            f.write(f"TOTP密钥: {'已配置' if config.get('totp_secret') else '未配置'}\n")
            f.write(f"代理设置: {config.get('proxy', '无')}\n")
            f.write(f"超时时间: {config.get('timeout', 30)}秒\n")
            f.write(f"最大重试: {config.get('max_retries', 3)}次\n")
            if log_file:
                f.write(f"日志文件: {log_file}\n")
            f.write("\n")
          
            # 测试结果统计
            vulnerabilities = result.get('vulnerabilities', [])
            f.write(f"发现安全问题: {len(vulnerabilities)}个\n")
            f.write("\n")
          
            # 详细漏洞信息
            if vulnerabilities:
                f.write("安全问题详情:\n")
                f.write("-" * 40 + "\n")
                for i, vuln in enumerate(vulnerabilities, 1):
                    f.write(f"{i}. {vuln}\n")
                f.write("\n")
            else:
                f.write("[+] 未发现明显的安全问题\n\n")
          
            # 安全建议
            recommendations = result.get('recommendations', [])
            if recommendations:
                f.write("安全建议:\n")
                f.write("-" * 40 + "\n")
                for rec in recommendations:
                    f.write(f"• {rec}\n")
                f.write("\n")
          
            # 详细分析
            detailed_analysis = result.get('detailed_analysis', {})
            if detailed_analysis:
                f.write("详细测试结果:\n")
                f.write("-" * 40 + "\n")
                for test_name, results in detailed_analysis.items():
                    if results:
                        test_title = test_name.replace('_', ' ').title()
                        f.write(f"\n{test_title}:\n")
                        for result_item in results:
                            f.write(f"  • {result_item}\n")
                f.write("\n")
          
            # 测试时间信息
            if result.get('test_start_time') and result.get('test_end_time'):
                test_duration = result['test_end_time'] - result['test_start_time']
                f.write(f"测试耗时: {test_duration}\n\n")
          
            f.write("=" * 80 + "\n")
            f.write("报告生成完成\n")
            f.write("=" * 80 + "\n")
      
        return report_file
    except Exception as e:
        print(f"生成报告文件时出错: {str(e)}")
        raise

if __name__ == "__main__":
    main()   